package com.yituo.mjworld.core.web.core;

import com.yituo.mjworld.core.annotation.Rules;
import com.yituo.mjworld.core.utils.ValidateTool;
import com.yituo.mjworld.mvc.form.IBaseForm;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * 基础扩展类
 *
 * @author xq
 */
public abstract class BaseForm implements IBaseForm {
  /**
   * 错误消息
   */
  protected String mErrorMsg;
  /**
   * 自身的实例,由外部指定.
   */
  private BaseForm mBaseForm;

  public BaseForm getBaseForm() {
    return mBaseForm;
  }

  public void setBaseForm(BaseForm mBaseForm) {
    this.mBaseForm = mBaseForm;
  }

  /**
   * 前端参数校验通过后.
   * <p>
   * 比如前端传递了一个startDate值.
   * <p>
   * 框架首先要做的是，时校验startDate的值是否符合规范.不符合规范则validate返回假,并可通过getErrorMsg获取到失败原因.
   * <p>
   * 参数校验通过后,这个参数转换为Date对象,放入Param中,在dao层将直接对该param进行遍历,并组装SQL.
   * <p>
   * 可以被数据库直接转换的参数列表.
   */
  private Map<String, Object> mParam;


  /**
   * 获取验证错误的消息.
   *
   * @return
   */
  public String getErrorMsg() {
    return this.mErrorMsg;
  }

  /**
   * 返回参数
   *
   * @return
   */
  public Map<String, Object> getParam() {
    return this.mParam;
  }

  public void setParam(Map<String, Object> params) {
    this.mParam = params;
  }


  /**
   * .将request.getParameterMap转换为另一种map
   */
  protected void parse(Map<String, Object> params) {
    this.mParam = new HashMap<String, Object>();
    for (String key : params.keySet()) {
      if (params.get(key) instanceof Object[]) {
        Object[] values = (Object[]) params.get(key);
        if (values != null && values.length == 1) {
          mParam.put(key, values[0]);
        } else if (values != null && values.length > 1) {
          mParam.put(key, values);
        }
      }
    }
  }

  /**
   * 初始化
   *
   * @param target
   * @param params
   * @return
   */
  @Override
  public boolean init(BaseForm target, Map<String, Object> params) {
    boolean result = false;
    parse(params);
    try {
      // 1.复制web参数的值到表单对象上
      BeanUtils.populate(target, params);
      // 2.保存对应的表单实例
      this.mBaseForm = (BaseForm) target;
      // 3.保存对应的字段
      result = true;
    } catch (IllegalAccessException e) {
      result = false;
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      result = false;
      e.printStackTrace();
    }
    return result;
  }

  /**
   * 验证.
   * <p>
   * 具体的内容由继承的子类实现
   *
   * @return
   */
  @Override
  public abstract boolean validate();


  /**
   * 默认的验证方法
   *
   * @return
   */
  protected boolean defaultValidate() {
    // 注意:该方法仅能读写公有方法
    Field[] fields = this.mBaseForm.getClass().getFields();
    for (Field field : fields) {
      if (field.isAnnotationPresent(Rules.class)) {
        // 对注解类进行分析
        Rules rule = field.getAnnotation(Rules.class);
        // 默认值
        String defaultValue = rule.defaultValue();
        // 其他校验项
        String sMin = rule.min();
        String sMax = rule.max();
        int length = rule.length();
        boolean required = rule.required();
        int min = 0;
        int max = 0;
        boolean id = rule.id();
        try {
          if (!"null".equals(sMin)) {
            min = Integer.parseInt(sMin);
          }
          if (!"null".equals(sMax)) {
            max = Integer.parseInt(sMax);
          }
        } catch (Exception e) {
          // 开发者的配置出错.
          e.printStackTrace();
          this.mErrorMsg = getError(field, "请连续后端管理人员解决.");
          return false;
        }
        Object fieldValue = null;
        try {
          fieldValue = field.get(this.mBaseForm);
          // 1.过滤主键列
          if (id) {
            if (fieldValue == null) {
              continue;
            }
          }
          // 2.填写默认值
          if (!"null".equals(defaultValue)) {
            if (field.getType() == Integer.class) {
              field.setInt(this.mBaseForm, Integer.parseInt(defaultValue));
            }
            if (field.getType() == String.class) {
              field.set(this.mBaseForm, defaultValue);
            }
          }
        } catch (IllegalAccessException e) {
          e.printStackTrace();
          this.mErrorMsg = getError(field, "值读写失败!");
          return false;
        }
        // 3.必填项校验
        if (required == true && ValidateTool.isEmpty(fieldValue)) {
          this.mErrorMsg = getError(field, "必填项不能为空");
          return false;
        }
        // 4.长度校验
        if (length >= 0 && ValidateTool.length(fieldValue, length)) {
          this.mErrorMsg = getError(field, "长度不符合");
          return false;
        }
        // 5.校验是否最小值
        if (fieldValue != null && !"null".equals(sMin) && ValidateTool.min(fieldValue, min)) {
          this.mErrorMsg = getError(field, "小于最小值!");
          return false;
        }
        // 6.校验最大值
        if (fieldValue != null && !"null".equals(sMax) && ValidateTool.max(fieldValue, max)) {
          this.mErrorMsg = getError(field, "大于最大值!");
          return false;
        }
      }
    }
    return true;
  }


  /**
   * 默认的错误信息生成策略.
   * <p>
   *
   * @param field
   * @return
   */
  private String getError(Field field, String error) {
    // 对注解类进行分析
    String errorMsg = "";
    String fieldName = "";
    if (field != null) {
      Rules rule = field.getAnnotation(Rules.class);
      errorMsg = rule.errorMsg();
      fieldName = rule.fieldName();
    } else {
      fieldName = "program error!";
    }
    if (StringUtils.isEmpty(fieldName)) {
      fieldName = field.getName();
    }
    if (StringUtils.isEmpty(errorMsg)) {
      if (StringUtils.isEmpty(error)) {
        errorMsg = "validate error!";
      } else {
        errorMsg = error;
      }
    }
    return new StringBuilder(fieldName).append(errorMsg).toString();
  }


}
